package stream.method;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

import java.math.BigDecimal;
import java.util.*;
import java.io.*;


/**
 * @CreateBy zhangdingyi
 * @Date 2022-10-07
 * @Content Optional 的具体使用
 */
public class Four {
    public static void main(String[] args) {
        //创建 Optional
        //createOptional();

        //基本使用 Optional
        //testIfPresent();

        //书上代码
        // testUseOptional();
        testUseOptional2();

    }

    /**
     * 使用 Optional 的代码清单
     * 简单的讲 Optional 就是判断一个对象是否为空值，如果是空值，可以按照所设置的数据进行返回
     */
    static void testUseOptional() {
        String contents = "test,fred,test123,fred123,optional,optional123";
        List<String> list = Arrays.asList(contents.split(","));
        //这里是 判断符合 test1a 条件的数据是否存在，如果存在 就是直接输出，不存在就输出 no data
        Optional<String> optional = list.stream()
                .filter(s -> s.contains("test1")).findAny();
        System.out.println(optional.orElse("no data" + " test"));

        //如果 这个 Optional 值 是空 那么就 直接输出 orElse("N/A") 中的 N/A
        Optional<String> optional2 = Optional.empty();
        String result = optional2.orElse("N/A");
        System.out.println("result -> " + result);

        //往集合中添加数据
        List<String> testAdd = new ArrayList<>();
        //这里可以添加数据 -如果有值就添加到 testAdd 集合中
        optional.ifPresent(testAdd::add);
        //这个也是同理
        Optional<Boolean> aBoolean = optional.map(testAdd::add);
        System.out.println("aBoolean -> " + aBoolean);
        System.out.println("testAdd.size -> " + testAdd.size());
        System.out.println("testAdd 1-> " + testAdd.get(0));
        System.out.println("testAdd 2-> " + testAdd.get(1));

    }

    /**
     * 代码清单 2
     * 方法引用
     * 这里的意思是 重复的调用某一个方法来处理同一个值
     * （不同方法来处理同一个值也行）
     * <p>
     * ·<U>Optional<U>flatMap（Function<？super T，Optional<U>>mapper）
     * 简单的说就是调用某个方法来处理  Optional 的值，可以重复调用、多次调用
     * 产生将mapper应用于当前的Optional值所产生的结果，或者在当前Optional为空时，
     * 返回一个空Optional。
     */
    static void testUseOptional2() {
        //Optional[0.5]
        System.out.println(inverse(4.0).flatMap(Four::square));
        //Optional[NaN]
        System.out.println(inverse(-1.0).flatMap(Four::square));
        //Optional.empty
        System.out.println(inverse(0.0).flatMap(Four::square));
        //aDouble -> Optional[Optional.empty]
        Optional<Optional<Double>> aDouble = Optional.of(-4.0)
                .flatMap(Four::inverse).map(Four::square);
        System.out.println("aDouble -> " + aDouble);

        //Optional.empty
        Optional<Double> aDouble2 = Optional.of(-5.0)
                .flatMap(Four::inverse) //; //Optional[-0.2]
                .flatMap(Four::square)
                .flatMap(Four::square);
        System.out.println("aDouble2 -> " + aDouble2);

    }

    /**
     * 定义一个方法，使用该方法时传入一个数据使其变成 分数形式
     *
     * @param x
     * @return
     */
    static Optional<Double> inverse(Double x) {
        return x == 0 ? Optional.empty() : Optional.of(1 / x);
    }

    /**
     * 定义一个方法，使用方法时，传入一个数据 返回一个 四舍五入正平方根
     *
     * @param x
     * @return
     */
    static Optional<Double> square(Double x) {
        return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
    }

    /**
     * ·void ifPresent（Consumer<？super T>consumer）
     * ifPresent()这个也可以接收一个函数 --如果值存在就进入该函数 ，不存在就不进行操作
     * 如果该Optional不为空，那么就将它的值传递给consumer。
     * <p>
     * ·<U>Optional<U>map（Function<？super T，？extends U>mapper）
     * 简单的说就是 循环数据，如果有值就是当前的值，如果有值就是 空 绝对不会是null 值，因为如果是null 在创建赋值的时候就会直接报错了
     * 产生将该Optional的值传递给mapper后的结果，只要这个Optional不为空且结果不为null，否则产生一个空Optional。
     * <p>
     * get 产生这个Optional的值，或者在该Optional为空时，抛出一个NoSuchElementException对象
     * <p>
     * isPresent 如果该Optional不为空，则返回true
     */
    private static void testIfPresent() {
        Optional<String> optional = Optional.ofNullable("123");
        //如果值存在就返回 true
        boolean present = optional.isPresent();
        System.out.println(present);
        // ifPresent()这个也可以接收一个函数 --如果值存在就进入该函数 ，不存在就不进行操作
        optional.ifPresent(v -> v.equals("123"));
        //map 也是同理 ，如果有值就直接进行操作，没有就不操作
        optional.map(v -> {
            System.out.println(v);
            return v;
        });

        //get 是获取值
        String s = optional.get();
        System.out.println("get -> " + s);

        //如果在设置值的时候设置为null 那么该数据也会保错 No value present
        Optional<String> optional2 = Optional.ofNullable(null);
        String s2 = optional2.get();
        System.out.println("get2 -> " + s2);
    }

    /**
     * ofNullable 创建 一个 Optional 对象，如果是 null 就创建一个 空的 Optional对象
     * <p>
     * ·T orElse（T other） 表示 当其 是 空 的时候就就输出 某个值
     * 产生这个Optional的值，或者在该Optional为空时，产生other。
     * <p>
     * ·T orElseGet（Supplier<？extends T>other） 表示 当其 是 空的时候就可以调用该方法得出某个值
     * 产生这个Optional的值，或者在该Optional为空时，产生调用other的结果。
     * <p>
     * ·T orElseThrow（Supplier<？extends X>exceptionSupplier）
     * orElseThrow 表示 当其 是 空的时候就可以抛出异常
     * 产生这个Optional的值，或者在该Optional为空时，抛出调用exceptionSupplier的结果。
     */
    private static void createOptional() {
        //这个是单例模式
        //这里创建 一个值 ，如果这个值 是null 那么创建处理的值就是 创建一个 空 empty() 对象
        Optional<String> optional = Optional.ofNullable(null);
        //orElse 如果 optional 是 null 就设置值为 123
        String result = optional.orElse("123");
        System.out.println(result);

        //String result2 = optional.orElseGet(()-> Locale.getDefault().getDisplayName());
        // orElseGet 如果 值为 null 可以利用方法来 赋值
        String result2 = optional.orElseGet(() -> BigDecimal.ZERO + "");
        System.out.println(result2);

        // 测试一下 BigDecimal 类
        Optional<BigDecimal> number = Optional.ofNullable(BigDecimal.ZERO);
        BigDecimal bigDecimal = number.orElse(BigDecimal.ONE);
        System.out.println(bigDecimal);

        //如果 值为 null 就直接抛出异常
        String result3 = optional.orElseThrow(IllegalAccessError::new);
        System.out.println(result3);

    }


}
